package cz.possoft.serializable.clovece.game;

import java.util.Collection;
import java.util.HashSet;

import cz.possoft.generic.utils.GenericUtils;
import cz.possoft.serializable.generic.HraciPole;

/**
 * @author <a href="mailto:mposolda@gmail.com">Marek Posolda</a>
 */
public class ClovecePole extends HraciPole
{
   public static final long serialVersionUID = 10049991;
   
   // Number of field on the pane (not cover home fields)
   public static final int LENGTH = 40;
   
   private CloveceField[] fields;
   
   private CloveceField[] blackPlayerHomeFields;
   private CloveceField[] whitePlayerHomeFields;
   
   private CloveceField[] blackPlayerStartFields;
   private CloveceField[] whitePlayerStartFields; 
   
   // reference to start fields of players.
   public static final int WHITE_PLAYER_START_FIELD_ON_BOARD = 0;   
   public static final int BLACK_PLAYER_START_FIELD_ON_BOARD = 20;   
   
   public ClovecePole()
   {
      // init main part of the HraciPole
      fields = new CloveceField[LENGTH];
      for (int i=0 ; i<LENGTH ; i++)
      {
         fields[i] = new CloveceField(i);
      }
      
      // init home fields
      whitePlayerHomeFields = new CloveceField[4];
      for (int i=0 ; i<4 ; i++)
      {
         whitePlayerHomeFields[i] = new CloveceField(100+i);
      }            
      blackPlayerHomeFields = new CloveceField[4];
      for (int i=0 ; i<4 ; i++)
      {
         blackPlayerHomeFields[i] = new CloveceField(200+i);
      } 
      
      // init start fields
      whitePlayerStartFields = new CloveceField[4];
      for (int i=0 ; i<4 ; i++)
      {
         whitePlayerStartFields[i] = new CloveceField(1000+i);
      }            
      blackPlayerStartFields = new CloveceField[4];
      for (int i=0 ; i<4 ; i++)
      {
         blackPlayerStartFields[i] = new CloveceField(2000+i);
      }   
      
      // initialize neighbours
      for (int i=0 ; i<LENGTH ; i++)
      {
         if (i != LENGTH-1)
         {
            fields[i].setNeighbourFromDirection(fields[i+1]);
         }
         else
         {
            fields[i].setNeighbourFromDirection(fields[0]);
         }         
      }
      
      whitePlayerHomeFields[0].setNeighbourFromDirection(fields[1]);      
      blackPlayerHomeFields[0].setNeighbourFromDirection(fields[21]);      
      
      for (int i=1 ; i<4 ; i++)
      {
         whitePlayerHomeFields[i].setNeighbourFromDirection(whitePlayerHomeFields[i-1]);
         blackPlayerHomeFields[i].setNeighbourFromDirection(blackPlayerHomeFields[i-1]);     
      }
   }     
   
   /**
    * return specified field from the pane.
    * 
    * @param location
    * @return
    */
   public CloveceField getField(int location)
   {
      return fields[location];
   }
   
   /**
    * return home field of some player.
    *      
    * @param location
    * @param color
    * @return
    */
   public CloveceField getHomeField(int location, int color)
   {
      if (color == GenericUtils.COLOR_BLACK)
      {
         return blackPlayerHomeFields[location];
      }
      else if (color == GenericUtils.COLOR_WHITE)
      {
         return whitePlayerHomeFields[location];
      }
      
      throw new IllegalArgumentException("Input can be only black color or white color. But input was: " + color);
   }   
   
   /**
    * return start field of some player.
    *      
    * @param location
    * @param color
    * @return
    */
   public CloveceField getStartField(int location, int color)
   {
      if (color == GenericUtils.COLOR_BLACK)
      {
         return blackPlayerStartFields[location];
      }
      else if (color == GenericUtils.COLOR_WHITE)
      {
         return whitePlayerStartFields[location];
      }
      
      throw new IllegalArgumentException("Input can be only black color or white color. But input was: " + color);
   }
   
   /**
    * get field based on id
    *      
    * @param fieldId
    * @return field with specified id
    */
   public CloveceField getFieldById(int fieldId)
   {
      if (fieldId < 50)
      {
         return getField(fieldId);
      }
      else if (fieldId < 199)
      {
         return getHomeField(fieldId - 100, GenericUtils.COLOR_WHITE);
      }
      else if (fieldId < 299)
      {
         return getHomeField(fieldId - 200, GenericUtils.COLOR_BLACK);
      }      
      else if (fieldId < 1100)
      {
         return getStartField(fieldId - 1000, GenericUtils.COLOR_WHITE);
      }
      else if (fieldId < 2100)
      {
         return getStartField(fieldId - 2000, GenericUtils.COLOR_BLACK);
      }   
      
      throw new IllegalArgumentException("Not valid id: " + fieldId);
   }
   
   /**
    * return all fields where our CloveceField (with figurka) can play
    * 
    * @param ourField field which we are interested.
    * @param pocetTahu 
    * @param color of our figurka
    * @return collection of all fields where we can play 
    */
   public Collection<CloveceField> getFieldsWhereFigurkaCanPlay(CloveceField ourField, int pocetTahu, int color)
   {
      // special case - ourField is start field and we have 6
      if ((ourField.getId() > 999) && (pocetTahu == 6))
      {
         Collection<CloveceField> results = new HashSet<CloveceField>();
         if (color == GenericUtils.COLOR_WHITE)
         {
            // we can't play only if there is our figurka on the starting field of the board.
            CloveceField startFieldOfBoard = getField(WHITE_PLAYER_START_FIELD_ON_BOARD);
            if (startFieldOfBoard.getColor() != GenericUtils.COLOR_WHITE)
            {
               results.add(startFieldOfBoard);
            }
         }
         else
         {
            // we can't play only if there is our figurka on the starting field of the board.
            CloveceField startFieldOfBoard = getField(BLACK_PLAYER_START_FIELD_ON_BOARD);
            if (startFieldOfBoard.getColor() != GenericUtils.COLOR_BLACK)
            {
               results.add(startFieldOfBoard);
            }                                    
         }
         
         return results;
      }      
      
      Collection<CloveceField> resultsForNextField = ourField.getNeighborsToDirection();
      
      Collection<CloveceField> results = new HashSet<CloveceField>();
            
      for (CloveceField nextField : resultsForNextField)
      {
         // we need to play to our 'domecek' if we have possibility to go here.
         if (nextField.isPartOfHome(color))
         {
            results.clear();
            // we can go to 'domecek' only if there is no our other figurka on specified place 
            if ((nextField.getColor() == GenericUtils.COLOR_NEUTRAL) || (pocetTahu > 1))
            {
               results.add(nextField);
            }
            break;
         }  
         // we can't play to the home of second player
         if (!nextField.isPartOfHome(GenericUtils.getOppositeColor(color)))
         {
            results.add(nextField);
         } 
         // we can't play to field where is figurka of same color (We can't 'vyhodit' our own figurka)
         if ((pocetTahu == 1) && (nextField.getColor() == color))
         {
            results.remove(nextField);
         }         
      }
      
      if (pocetTahu == 1)
      {
         return results;
      }
      else
      {
         Collection<CloveceField> finalResults = new HashSet<CloveceField>();

         // Now we need to use recursion
         for (CloveceField currField : results)
         {
            Collection<CloveceField> fields = getFieldsWhereFigurkaCanPlay(currField, pocetTahu - 1, color);
            finalResults.addAll(fields);
         }
         
         return finalResults;            
      }                          
   }      

}

